package de.bazinga.rotw.weapon;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import com.jme.animation.SpatialTransformer;
import com.jme.input.MouseInput;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.state.CullState;
import com.jme.scene.state.ZBufferState;
import com.jmex.audio.AudioTrack;
import com.jmex.game.state.GameStateManager;

import de.bazinga.rotw.game.Game;
import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.model.ModelCache;
import de.bazinga.rotw.network.BasicSyncManager;
import de.bazinga.rotw.network.Client;
import de.bazinga.rotw.network.Server;
import de.bazinga.rotw.network.message.NewBulletMessage;
import de.bazinga.rotw.person.Person;
import de.bazinga.rotw.player.Player;
import de.bazinga.rotw.sound.Sound;
import de.bazinga.rotw.texture.TextureCache;

public class Knife extends Weapon {	
	
	public static final int TOPTHIRD_DAMAGE = 51;
	public static final int MIDDLETHIRD_DAMAGE = 50;
	public static final int BOTTOMTHIRD_DAMAGE = 34;
	
	private int ammo = -1;
	protected long lastShoot = 0;
	
	
	protected static Node weaponModel = null;
	protected static SpatialTransformer st = null;
	
	
	public Knife() {
		this.ammo = -1;
	}
	
	
	public void updateWeapon(Player player) {
		// Fire?
		
		if(MouseInput.get().isButtonDown(0)) {
			BasicSyncManager syncManager = 
				((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getSyncManager();
			
			NewBulletMessage newBulletMessage = new NewBulletMessage();
			newBulletMessage.setWeaponFlag(NewBulletMessage.KNIFE);
			newBulletMessage.setLocation(player.getCameraPosition().clone());
			newBulletMessage.setDirection(Game.getGame().getCamera().getDirection().clone());
			newBulletMessage.setBulletColor(player.getBulletColor());
			
			
			if(canFire()) {
				// Animate
				if(st != null) {
					st.setCurTime(0);
					st.setActive(true);
				}
				
				if(syncManager instanceof Server) {
					// Tell the Clients to play Sound!
					((Server)syncManager).getServer().sendToAll(newBulletMessage);
					
					// Just Fire the bullet
					fireBullet(player,player.getCameraPosition().clone(), Game.getGame().getCamera().getDirection().clone(), false);
					player.fired();
				}else if(syncManager instanceof Client) {
					((Client) syncManager).getClient().sendToServer(newBulletMessage);
					player.fired();
				}
			}
		}
	}

	
	
	/**
	 * Only the Server will call this
	 */
	public void fireBullet(Person person, Vector3f location, Vector3f direction, boolean fromClient) {
		
		Weapon.fireBullet(person, location, direction, NewBulletMessage.KNIFE, 2f, 
				Knife.TOPTHIRD_DAMAGE, Knife.MIDDLETHIRD_DAMAGE, Knife.BOTTOMTHIRD_DAMAGE, 
				Knife.TOPTHIRD_DAMAGE, Knife.MIDDLETHIRD_DAMAGE, Knife.BOTTOMTHIRD_DAMAGE, 
				10, false, false);
	}


	
	/**
	 * Can the player fire again?
	 * Checks if he can fire again and if he has enough Ammo (also subtracts ammo)
	 * @return
	 */
	public boolean canFire() {
		if((System.currentTimeMillis() - lastShoot) < 700 )
			return false;
		
		/*if(ammo == 0)
			return false;
		*/
		lastShoot = System.currentTimeMillis();
		
		//ammo--;
		
		return true;
	}
	
	
	
	
	public String getIcon() {
		return "knife.png";
	}
	
	
	public Node getWeaponModel() {
		if(weaponModel == null) {
			initWeaponModel();
		}
		return weaponModel;
	}
	
	public static void initWeaponModel() {
		if(weaponModel == null) {
			weaponModel = new Node("weapon");
			// Load Model
			URL textureUrl = null;
			URL textureUrl1 = null;
			try {
				textureUrl = new File("weapons/").toURI().toURL();
				textureUrl1 = new File("weapons/parabolic_knife_COLOR.png").toURI().toURL();
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			}
			
			
			Node weapon = ModelCache.getInstance().addModel(textureUrl, textureUrl, "/weapons/parabolic_knife.3DS");
			
			
	        weapon.setLocalScale(0.27f);
	        
	        weapon.setRenderState(TextureCache.getInstance().getTexture(textureUrl1));
	        weapon.updateRenderState();
	        
	        weapon.detachChildNamed("physic");
	        
	        Quaternion rot = new Quaternion();
	        rot.fromAngleAxis(180*FastMath.DEG_TO_RAD, Vector3f.UNIT_X);
	        weapon.setLocalRotation(rot);
	        
	        
	        Node animationNode = new Node("knifeanimation");
			Quaternion rot0 = new Quaternion();
			rot0.fromAngleAxis(5*FastMath.DEG_TO_RAD, Vector3f.UNIT_Y);
			animationNode.setLocalRotation(rot0);
	        animationNode.attachChild(weapon);
	        
	        
	        Node rotNode = new Node("rot");
	        rotNode.setLocalTranslation(new Vector3f(-1.5f,-1.6f,5));
	        rotNode.attachChild(animationNode);
	        
	        Quaternion rot1 = new Quaternion();
	        rot1.fromAngleAxis(80*FastMath.DEG_TO_RAD, Vector3f.UNIT_Z);
	        rotNode.setLocalRotation(rot1);
	        

	        ZBufferState zBuffer = Game.getGame().getDisplay().getRenderer().createZBufferState();
	        zBuffer.setEnabled(true);
	        zBuffer.setFunction(ZBufferState.TestFunction.Always);
	        rotNode.setRenderState(zBuffer);
	        
	        CullState culling = Game.getGame().getDisplay().getRenderer().createCullState();
	        culling.setEnabled(true);
	        culling.setCullFace(CullState.Face.Back);
	        rotNode.setRenderState(culling);
	        
	        
	        
	        st = new SpatialTransformer(1);
			st.setObject(animationNode, 0, -1);
			st.setSpeed(10f);
			st.setRepeatType(SpatialTransformer.RT_CLAMP);
			st.setActive(false);
			
			
			st.setPosition(0, 0, new Vector3f(0,0,0));
			st.setRotation(0, 0, rot0);
			
			st.setPosition(0, 1, new Vector3f(0,0,1));
			Quaternion rot45 = new Quaternion();
			rot45.fromAngleAxis((0-45)*FastMath.DEG_TO_RAD, Vector3f.UNIT_Y);
			st.setRotation(0, 1, rot45);
			
			st.setPosition(0, 2, new Vector3f(0,0,2));
			Quaternion rot90 = new Quaternion();
			rot90.fromAngleAxis((0-90)*FastMath.DEG_TO_RAD, Vector3f.UNIT_Y);
			st.setRotation(0, 2, rot90);
			
			st.setPosition(0, 3, new Vector3f(0,0,0));
			st.setRotation(0, 3, rot0);
			
			
			st.interpolateMissing();
			weaponModel.addController(st);
			
			
	        
	        
	        weaponModel.attachChild(rotNode);
		}
	}


	
	public void playerFired() {
		if(Game.getGame().getSettings().isSFX()) {
			Sound.getInstance().getAudioTrack("sounds/knife.wav").play();
		}
	}
	
	

	/**
	 * Another player fired from the given Location
	 */
	public static void otherPlayerFired(Vector3f location) {
		Player player = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getPlayer();
		
		if(Game.getGame().getSettings().isSFX() && player.getLocalTranslation().distance(location) < 30) {
			AudioTrack at = Sound.getInstance().getAudioTrack("sounds/knife.wav");
			at.setWorldPosition(location);
			at.play();
		}
	}

	
	public int getAmmo() {
		return ammo;
	}
	
	
	// We dont need this
	public boolean reload() {
		return false;
	}
	
	

	public void setAmmo(int ammo) {
		this.ammo = ammo;
	}


	public void refillAmmo() {
		ammo = -1;
	}
	
	public float getSpeedFactor() {
		return 1.05f;
	}
	
}